//////////////////////////////////////////////////////////////////////
//
// NO_Pointer.h
//
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
#ifndef RCRESPTR_H_
#define RCRESPTR_H_

//////////////////////////////////////////////////////////////////////
#include <cstddef>
#include "NO_PointerHolder.h"

//////////////////////////////////////////////////////////////////////
//class NO_Pointer 
//////////////////////////////////////////////////////////////////////////
template <class TargetClass>
class NO_Pointer
{
public:
	//////////////////////////////////////////////////////////////////////
	typedef NO_Pointer<TargetClass> Pointer;
	typedef NO_PointerHolder<TargetClass> Holder;
	typedef NO_PointerHolder<TargetClass>* HolderPointer;
	typedef TargetClass* PointerType;
	typedef TargetClass& ReferenceType;
	
	//////////////////////////////////////////////////////////////////////
	// con/des
	//////////////////////////////////////////////////////////////////////
	
	//////////////////////////////////////////////////////////////////////
	explicit NO_Pointer(HolderPointer pHolder = NULL)
	{
		ptrHolder = pHolder;
		if (ptrHolder != NULL)
			ptrHolder->addRef();    
	}
	
	//////////////////////////////////////////////////////////////////////
	NO_Pointer(const Pointer& rhs)
	{
		ptrHolder = rhs.ptrHolder;
		if (ptrHolder != NULL)
			ptrHolder->addRef();    
	}
	
	//////////////////////////////////////////////////////////////////////
	NO_Pointer(PointerType resource)
	{
		ptrHolder = new Holder(resource); 
		ptrHolder->addRef();    
	}
	
	//////////////////////////////////////////////////////////////////////
	~NO_Pointer()
	{
		if (ptrHolder != NULL)
			ptrHolder->remRef(); 
	}
	
	//////////////////////////////////////////////////////////////////////
	// operator
	//////////////////////////////////////////////////////////////////////
	
	//////////////////////////////////////////////////////////////////////
	Pointer& operator= (const Pointer& rhs)
	{
		if (ptrHolder == rhs.ptrHolder){return *this;}

		if (ptrHolder != NULL) {ptrHolder->remRef();}
		ptrHolder = rhs.ptrHolder;
		if (ptrHolder != NULL) {ptrHolder->addRef();}

		return *this;
	}
	
	//////////////////////////////////////////////////////////////////////
	Pointer& operator= (const PointerType rhs)
	{
		if (ptrHolder == NULL) 
		{
			if(rhs)
			{
				ptrHolder = new Holder(rhs);
				ptrHolder->addRef();
			}
			return *this;
		}

		if (ptrHolder->resource == rhs){return *this;}

		if (ptrHolder->resource != NULL) {ptrHolder->remRef();}
		ptrHolder->resource = rhs;
		if (ptrHolder->resource != NULL) {ptrHolder->addRef();}

		return *this;
	}
	
	//////////////////////////////////////////////////////////////////////
	PointerType operator->(void) const {return (ptrHolder->resource); }
	ReferenceType operator*(void) const {return *(ptrHolder->resource); }
	
	//////////////////////////////////////////////////////////////////////
	operator bool(void) const
	{
		if (ptrHolder == NULL)			{return false;}
		if (ptrHolder->resource == NULL){return false;}
		return true;
	}
	
	//////////////////////////////////////////////////////////////////////
	bool operator!(void) const
	{
		if (ptrHolder == NULL)			{return true;}
		if (ptrHolder->resource == NULL){return true;}
		return false;
	}
	
	//////////////////////////////////////////////////////////////////////
	bool operator==(const Pointer rhs) const
	{
		if (ptrHolder == rhs.ptrHolder)	{return true;}
		if (rhs.ptrHolder == NULL && ptrHolder->resource == NULL){return true;}
		if (ptrHolder == NULL && rhs.ptrHolder->resource == NULL){return true;}
		if (ptrHolder != NULL && rhs.ptrHolder != NULL &&
			ptrHolder->resource == rhs.ptrHolder->resource) {return true;}
		return false;
	}
	
	//////////////////////////////////////////////////////////////////////
	bool operator!=(const Pointer rhs) const 	
	{
		if (ptrHolder == rhs.ptrHolder){return false;}
		if (rhs.ptrHolder == NULL && ptrHolder->resource == NULL){return false;}
		if (ptrHolder == NULL && rhs.ptrHolder->resource == NULL){return false;}
		if (ptrHolder != NULL && rhs.ptrHolder != NULL &&
			ptrHolder->resource == rhs.ptrHolder->resource){return false;}
		return true;
	}
	
	//////////////////////////////////////////////////////////////////////
	bool operator==(const PointerType rhs) const
	{
		if (ptrHolder==0&&rhs==0)	 {return true;}
		if (ptrHolder->resource==rhs){return true;}
		return false;
	}
	
	//////////////////////////////////////////////////////////////////////
	bool operator!=(const PointerType rhs) const 	
	{
		if (ptrHolder==0&&rhs==0)	 {return false;}
		if (ptrHolder->resource==rhs){return false;}
		return true;
	}
	
	//////////////////////////////////////////////////////////////////////
	bool operator< (Pointer rhs) const
	{
		if (rhs.ptrHolder == NULL)	{return false;}
		if (ptrHolder == NULL)		{return true;}
		return (ptrHolder->resource < rhs.ptrHolder->resource);
	}
	
	//////////////////////////////////////////////////////////////////////
	// retrive
	//////////////////////////////////////////////////////////////////////
	const Holder& getPtrHolder(void) const {return *ptrHolder;}
	
//protected:
	HolderPointer ptrHolder;
};

#endif 
